﻿using Bilibili.Model.Common;
using Google.Protobuf;
using System;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;

namespace Bilibili.WebClient
{
    public sealed class GrpcRequest
    {
        private static GrpcRequest _instance;
        public static GrpcRequest Instance
        {
            get
            {
                if (_instance == null)
                    _instance = new GrpcRequest();
                return _instance;
            }
        }
        private HttpClient HttpClient { get; }
        private GrpcRequest()
        {
            HttpClient = new HttpClient();
        }
        public async Task<GrpcResult> SendMessage(string url, IMessage message, string access_key = "")
        {
            try
            {
                var config = new GrpcRequestHeaderConfig(access_key);
                StringBuilder uaBuilder = new StringBuilder();
                uaBuilder.Append($"Dalvik/{GrpcRequestHeaderConfig.dalvik_ver} ");
                uaBuilder.Append($"(Linux; U; Android {GrpcRequestHeaderConfig.os_ver}; {GrpcRequestHeaderConfig.brand} {GrpcRequestHeaderConfig.model}) {GrpcRequestHeaderConfig.app_ver} ");
                uaBuilder.Append($"os/android model/{GrpcRequestHeaderConfig.model} mobi_app/android build/{GrpcRequestHeaderConfig.build} ");
                uaBuilder.Append($"channel/{GrpcRequestHeaderConfig.channel} innerVer/{GrpcRequestHeaderConfig.build} osVer/{GrpcRequestHeaderConfig.os_ver} ");
                uaBuilder.Append($"network/{GrpcRequestHeaderConfig.network_type}");
                HttpClient.DefaultRequestHeaders.Add("User-Agent", uaBuilder.ToString());
                HttpClient.DefaultRequestHeaders.Add("APP-KEY", "android");
                HttpClient.DefaultRequestHeaders.Add("x-bili-metadata-bin", config.GetMetadataBin());
                HttpClient.DefaultRequestHeaders.Add("authorization", "identify_v1 " + access_key);
                HttpClient.DefaultRequestHeaders.Add("x-bili-device-bin", config.GetDeviceBin());
                HttpClient.DefaultRequestHeaders.Add("x-bili-network-bin", config.GetNetworkBin());
                HttpClient.DefaultRequestHeaders.Add("x-bili-restriction-bin", "");
                HttpClient.DefaultRequestHeaders.Add("x-bili-locale-bin", config.GetLocaleBin());
                HttpClient.DefaultRequestHeaders.Add("x-bili-fawkes-req-bin", config.GetFawkesreqBin());
                HttpClient.DefaultRequestHeaders.Add("grpc-accept-encoding", "identity");
                HttpClient.DefaultRequestHeaders.Add("grpc-timeout", "17985446u");
                HttpClient.DefaultRequestHeaders.Add("env", "prod");
                HttpClient.DefaultRequestHeaders.Add("Transfer-Encoding", "chunked");
                HttpClient.DefaultRequestHeaders.Add("TE", "trailers");
                var messageBytes = message.ToByteArray();
                var stateBytes = new byte[] { 0, 0, 0, 0, (byte)messageBytes.Length };
                byte[] bodyBytes = new byte[5 + messageBytes.Length];
                stateBytes.CopyTo(bodyBytes, 0);
                messageBytes.CopyTo(bodyBytes, 5);
                ByteArrayContent byteArrayContent = new ByteArrayContent(bodyBytes);
                byteArrayContent.Headers.ContentType = new MediaTypeHeaderValue("application/grpc");
                byteArrayContent.Headers.ContentLength = bodyBytes.Length;
                var response = await HttpClient.PostAsync(url, byteArrayContent);
                var data = await response.Content.ReadAsByteArrayAsync();
                if (data.Length > 5)
                {
                    return new GrpcResult
                    {
                        Code = 0,
                        Status = true,
                        Message = "请求成功",
                        Results = data.Skip(5).ToArray()
                    };
                }
                else
                {
                    return new GrpcResult
                    {
                        Code = -102,
                        Status = false,
                        Message = "请求失败,没有数据返回",
                    };
                }
            }
            catch (Exception ex)
            {
                return new GrpcResult
                {
                    Code = ex.HResult,
                    Status = false,
                    Message = "发送gRPC请求失败" + ex.Message
                };
            }
        }
        public async Task<GrpcResult> Get(string url)
        {
            try
            {
                using HttpClient httpClient = new HttpClient();
                var data = await httpClient.GetByteArrayAsync(url);
                if (data.Length > 5)
                {
                    return new GrpcResult
                    {
                        Code = 0,
                        Status = true,
                        Message = "请求成功",
                        Results = data.Skip(5).ToArray()
                    };
                }
                else
                {
                    return new GrpcResult
                    {
                        Code = -102,
                        Status = false,
                        Message = "请求失败,没有数据返回",
                    };
                }
            }
            catch (Exception ex)
            {
                return new GrpcResult
                {
                    Code = ex.HResult,
                    Status = false,
                    Message = "发送Http请求失败" + ex.Message
                };
            }
        }
    }
}